#include	"inc.h"

itq_t itq_create()
{
    itq_t   q;
    itq_msg_t *null_msg = NULL;
    pthread_t       tid;
    pthread_attr_t  thread_attr;

    Log(LOG_Z, "itq: create start\n");

    q = (itq_t)malloc(sizeof(it_queue_info_t));
    if(q == NULL) {
        Log(LOG_C, "itq: malloc info fail\n");
        return (itq_t) NULL;
    }

    null_msg = (itq_msg_t *)malloc(sizeof(itq_msg_t));
    if(null_msg == NULL) {
        free(q);
        Log(LOG_C, "itq: malloc msg fail\n");
        return (itq_t) NULL;
    }

    null_msg->len = 0; null_msg->next = NULL;

    q->itq_head = q->itq_tail = null_msg;
    q->itq_empty = 1;
    pthread_mutex_init(&q->itq_H_lock, NULL);
    pthread_mutex_init(&q->itq_T_lock, NULL);

    Log(LOG_Z, "itq: create end (%p)\n", q);

    return q;
}

int work_thread_create(int i, _THREAD_INFO *pThr, void*(*ThrFunc)(void*), void *pvParam, int nDetachF)
{
    itq_t   q;
    itq_msg_t *null_msg = NULL;
    pthread_t       tid[MAX_THREAD];
    pthread_attr_t  thread_attr;

    if( pthread_mutex_init( &pThr->lock, NULL ) != 0 )
    {
        Log( LOG_C, "Mutex Init Err[%d:%s]\n", errno, strerror(errno) );
        exit(1);
    }

    if( ThrFunc )
    {
        if( nDetachF )
        {
            if( pthread_attr_init( &thread_attr ) != 0 ) goto itq_create_error;
            pthread_attr_setdetachstate( &thread_attr, PTHREAD_CREATE_DETACHED );
            pthread_attr_setscope( &thread_attr, PTHREAD_SCOPE_SYSTEM );
        }

        if( pthread_create( &tid[i], NULL, ThrFunc, pvParam ) ) goto itq_create_error;
        if( nDetachF ) pthread_detach(tid[i]);

        Log( LOG_D, "ITQ THREAD CREATE SUCC!\n");
    }
    else { goto itq_create_error; }

    return SUCC;

itq_create_error :
    Log( LOG_C, "ITQ THREAD ATTR INIT FAIL - ERR[%d:%s]\n", errno, strerror(errno) );
    exit(1);
}

int itq_push(itq_t q, void *msg, int len)
{
    itq_msg_t *itq_msg = NULL;
    int       wakeup = 0;

    Log(LOG_Z, "itq: push start (%p)\n", q);

	if ( q == NULL ) return -1;

	if ( msg == NULL ) {
		Log(LOG_I, "itq: push msg null (%p)\n", msg);
		return -2;
	}

    wakeup = wakeup;
    /* copy the given data */
    itq_msg = (itq_msg_t *)malloc(sizeof(itq_msg_t) + len);
    if(itq_msg == NULL) return -1;
    itq_msg->len = len;
    memcpy(itq_msg->data, msg, len);
    itq_msg->next = NULL;

    pthread_mutex_lock(&q->itq_T_lock);
    q->itq_tail->next   = itq_msg;
    q->itq_tail         = itq_msg;
    pthread_mutex_unlock(&q->itq_T_lock);

    q->itq_empty = 0;
    return len;
}

int itq_pop(itq_t q, void *buf, int len)
{
    itq_msg_t   *node, *newhead;

    Log(LOG_Z, "itq: pop start (%p)\n", q);

	if ( q == NULL ) {
    	Log(LOG_I, "itq: q null (%p)\n", q);
		return -1;
	}

	if ( buf == NULL ) {
		Log(LOG_I, "itq: push buf null (%p)\n", buf);
		return -2;
	}

    pthread_mutex_lock(&q->itq_H_lock);

    if (q->itq_empty) {
        pthread_mutex_unlock(&q->itq_H_lock);
        return 0;
    }

    node = q->itq_head;
    newhead = node->next;
    if (newhead == NULL) {
        q->itq_empty = 1;
        pthread_mutex_unlock(&q->itq_H_lock);
        return -1;
    }
    /* copy value */
    len = newhead->len; /* len:value reference */
    memcpy(buf, newhead->data, newhead->len);

    q->itq_head = newhead;
    pthread_mutex_unlock(&q->itq_H_lock);
    free(node);

    if ( len < 0 ) Log(LOG_C, "itq_pop:: Fail (nLen %d)\n", len);
    else    if (len == 0)
		Log(LOG_Z, "itq_pop:: Empty (nLen %d)\n", len);
    else
		Log(LOG_I, "itq_pop:: Succ (nLen %d)\n", len);

    return len;
}
